package common

import (
	"douhu_backend/internal/config"
	"fmt"
	"time"

	"github.com/golang-jwt/jwt/v4"
)

// JWTClaims JWT声明结构
type JWTClaims struct {
	UserID    uint64 `json:"user_id"`
	Phone     string `json:"phone"`
	TokenType string `json:"token_type"` // access 或 refresh
	jwt.RegisteredClaims
}

// TokenPair Token对（access token + refresh token）
type TokenPair struct {
	AccessToken       string    `json:"access_token"`
	RefreshToken      string    `json:"refresh_token"`
	AccessExpiresAt   time.Time `json:"access_expires_at"`
	RefreshExpiresAt  time.Time `json:"refresh_expires_at"`
}

// JWTService JWT服务接口
type JWTService interface {
	// GenerateTokenPair 生成Token对（access token + refresh token）
	GenerateTokenPair(userID uint64, phone string) (*TokenPair, error)
	// GenerateToken 生成JWT token（废弃，保留兼容性）
	GenerateToken(userID uint64, phone string) (string, error)
	// ParseToken 解析JWT token
	ParseToken(tokenString string) (*JWTClaims, error)
	// RefreshToken 使用refresh token生成新的access token
	RefreshToken(refreshToken string) (*TokenPair, error)
}

// DefaultJWTService 默认JWT服务实现
type DefaultJWTService struct {
	config *config.JWT
}

// NewJWTService 创建JWT服务实例
func NewJWTService() (*DefaultJWTService, error) {
	jwtConfig := config.Conf.JWT
	if jwtConfig == nil {
		return nil, fmt.Errorf("jwt config is nil")
	}
	
	if jwtConfig.SecretKey == "" {
		return nil, fmt.Errorf("jwt secret key is empty")
	}

	return &DefaultJWTService{
		config: jwtConfig,
	}, nil
}

// GenerateTokenPair 生成Token对（access token + refresh token）
func (s *DefaultJWTService) GenerateTokenPair(userID uint64, phone string) (*TokenPair, error) {
	if s.config == nil {
		return nil, fmt.Errorf("jwt config is nil")
	}

	now := time.Now()
	issuer := s.config.Issuer
	if issuer == "" {
		issuer = "douhu"
	}

	// 生成 Access Token (3小时有效期)
	accessExpireTime := now.Add(3 * time.Hour)
	accessClaims := JWTClaims{
		UserID:    userID,
		Phone:     phone,
		TokenType: "access",
		RegisteredClaims: jwt.RegisteredClaims{
			Issuer:    issuer,
			IssuedAt:  jwt.NewNumericDate(now),
			ExpiresAt: jwt.NewNumericDate(accessExpireTime),
			NotBefore: jwt.NewNumericDate(now),
		},
	}
	accessToken := jwt.NewWithClaims(jwt.SigningMethodHS256, accessClaims)
	accessTokenString, err := accessToken.SignedString([]byte(s.config.SecretKey))
	if err != nil {
		return nil, fmt.Errorf("sign access token failed: %v", err)
	}

	// 生成 Refresh Token (30天有效期)
	refreshExpireTime := now.Add(30 * 24 * time.Hour)
	refreshClaims := JWTClaims{
		UserID:    userID,
		Phone:     phone,
		TokenType: "refresh",
		RegisteredClaims: jwt.RegisteredClaims{
			Issuer:    issuer,
			IssuedAt:  jwt.NewNumericDate(now),
			ExpiresAt: jwt.NewNumericDate(refreshExpireTime),
			NotBefore: jwt.NewNumericDate(now),
		},
	}
	refreshToken := jwt.NewWithClaims(jwt.SigningMethodHS256, refreshClaims)
	refreshTokenString, err := refreshToken.SignedString([]byte(s.config.SecretKey))
	if err != nil {
		return nil, fmt.Errorf("sign refresh token failed: %v", err)
	}

	return &TokenPair{
		AccessToken:      accessTokenString,
		RefreshToken:     refreshTokenString,
		AccessExpiresAt:  accessExpireTime,
		RefreshExpiresAt: refreshExpireTime,
	}, nil
}

// GenerateToken 生成JWT token（废弃，保留兼容性）
func (s *DefaultJWTService) GenerateToken(userID uint64, phone string) (string, error) {
	tokenPair, err := s.GenerateTokenPair(userID, phone)
	if err != nil {
		return "", err
	}
	return tokenPair.AccessToken, nil
}

// ParseToken 解析JWT token
func (s *DefaultJWTService) ParseToken(tokenString string) (*JWTClaims, error) {
	if s.config == nil {
		return nil, fmt.Errorf("jwt config is nil")
	}
	
	token, err := jwt.ParseWithClaims(tokenString, &JWTClaims{}, func(token *jwt.Token) (interface{}, error) {
		// 验证签名方法
		if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
			return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"])
		}
		return []byte(s.config.SecretKey), nil
	})

	if err != nil {
		return nil, fmt.Errorf("parse token failed: %v", err)
	}

	if claims, ok := token.Claims.(*JWTClaims); ok && token.Valid {
		return claims, nil
	}

	return nil, fmt.Errorf("invalid token")
}

// RefreshToken 使用refresh token生成新的Token对
func (s *DefaultJWTService) RefreshToken(refreshToken string) (*TokenPair, error) {
	claims, err := s.ParseToken(refreshToken)
	if err != nil {
		return nil, fmt.Errorf("parse refresh token failed: %v", err)
	}

	// 验证是否为refresh token
	if claims.TokenType != "refresh" {
		return nil, fmt.Errorf("invalid token type, expected refresh token")
	}

	// 生成新的Token对
	newTokenPair, err := s.GenerateTokenPair(claims.UserID, claims.Phone)
	if err != nil {
		return nil, fmt.Errorf("generate new token pair failed: %v", err)
	}

	return newTokenPair, nil
}

// GetExpireHours 获取token过期时间（小时）
func (s *DefaultJWTService) GetExpireHours() int {
	if s.config == nil {
		return 24 // 默认24小时
	}
	if s.config.ExpireHours <= 0 {
		return 24 // 默认24小时
	}
	return s.config.ExpireHours
}